// FacebookLoginForm.cs
// Facebook/FrameworkDesktop/Service
// Copyright (c) 2007, Nikhil Kothari. All Rights Reserved.
//

using System;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using Facebook.Service;
using Facebook.Service.Core;

namespace Facebook.Desktop {

    internal sealed partial class FacebookLoginForm : Form {

        private const string LoginUrlFormat =
            @"http://www.facebook.com/login.php?api_key={0}&v=1.0&popup&skipcookie&auth_token={1}";

        private const string LoadingHtml =
            @"<span style=""font-family: tahoma; font-size: 8pt"">Loading...</span>";

        private FacebookSession _session;
        private string _sessionKey;
        private string _userID;
        private bool _sessionExpires;
        private string _secret;
        private string _authToken;

        private bool _retrying;

        private FacebookRequest _request;
        private IAsyncResult _createAuthTokenAsyncResult;
        private IAsyncResult _createSessionAsyncResult;

        public FacebookLoginForm(FacebookClientSession session) {
            Debug.Assert(session != null);
            _session = session;

            InitializeComponent();
        }

        public string Secret {
            get {
                return _secret;
            }
        }

        public bool SessionExpires {
            get {
                return _sessionExpires;
            }
        }

        public string SessionKey {
            get {
                if (_sessionKey == null) {
                    return String.Empty;
                }
                return _sessionKey;
            }
        }

        public string UserID {
            get {
                return _userID;
            }
        }

        private void AbortLogin() {
            DialogResult = DialogResult.Cancel;
            Close();
        }

        private void AcquireToken() {
            if (_retrying) {
                if (MessageBox.Show(this, "The attempt to create a Facebook session failed. Try Again?", Text,
                                    MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) == DialogResult.No) {
                    AbortLogin();
                }
            }

            try {
                _createAuthTokenAsyncResult = _request.BeginCreateAuthToken(OnCreateAuthTokenCallback, null);
            }
            catch (Exception ex) {
                Debug.Fail(ex.ToString());

                DialogResult = DialogResult.Cancel;
                Close();
            }
        }

        private void CompleteLogin() {
            DialogResult = DialogResult.OK;
            Close();
        }

        private void OnCancelButtonClick(object sender, EventArgs e) {
            if (_createAuthTokenAsyncResult != null) {
                // TODO: Abort
            }
            if (_createSessionAsyncResult != null) {
                // TODO: Abort
            }

            DialogResult = DialogResult.Cancel;
            Close();
        }

        protected override void OnActivated(EventArgs e) {
            base.OnActivated(e);

            if (_request == null) {
                _webBrowser.DocumentText = LoadingHtml;
                _request = new FacebookRequest(_session);

                AcquireToken();
            }
        }

        private void OnCreateAuthTokenCallback(IAsyncResult asyncResult) {
            _createAuthTokenAsyncResult = null;
            try {
                _authToken = _request.EndCreateAuthToken(asyncResult);
                Invoke(new MethodInvoker(StartLogin));
            }
            catch {
            }
        }

        private void OnCreateSessionCallback(IAsyncResult asyncResult) {
            _createSessionAsyncResult = null;
            try {
                _sessionKey = _request.EndCreateSession(asyncResult, out _userID, out _sessionExpires, out _secret);
                Debug.Assert(String.IsNullOrEmpty(_secret) == false);

                if (String.IsNullOrEmpty(_secret)) {
                    if (_retrying) {
                        Invoke(new MethodInvoker(AbortLogin));
                    }
                    else {
                        _retrying = true;
                        Invoke(new MethodInvoker(AcquireToken));
                    }
                }
                else {
                    Invoke(new MethodInvoker(CompleteLogin));
                }
            }
            catch {
            }
        }

        private void OnWebBrowserNavigated(object sender, WebBrowserNavigatedEventArgs e) {
            if (e.Url.PathAndQuery.Contains("desktopapp.php")) {
                _createSessionAsyncResult = _request.BeginCreateSession(_authToken, OnCreateSessionCallback, null);
            }
        }

        private void StartLogin() {
            string loginUrl = String.Format(LoginUrlFormat, _session.ApplicationKey, _authToken);
            _webBrowser.Navigate(loginUrl);
        }
    }
}
